home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Java 1996 August
/
Java - Summer 1996.iso
/
kaffe-0.2
/
kaffe
/
thread.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-02-19
|
8KB
|
411 lines
/*
* thread.c
* Thread support.
*
* Copyright (c) 1996 Systems Architecture Research Centre,
* City University, London, UK.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* Written by Tim Wilkinson <tim@sarc.city.ac.uk>, February 1996.
*/
#include <assert.h>
#include <string.h>
#include "classMethod.h"
#include "baseClasses.h"
#include "object.h"
#include "thread.h"
#include "locks.h"
#include "md.h"
thread* threadQhead[MAX_THREAD_PRIO + 1];
thread* threadQtail[MAX_THREAD_PRIO + 1];
thread* finalman;
thread* gcman;
thread* currentThread;
classes* ThreadClass;
int blockInts;
bool needReschedule;
static int talive;
static int tdaemon;
extern classes* ClassClass;
void reschedule(void);
static void firstStartThread(void);
static thread* startDaemon(void*);
void finaliserMan(void);
void gcMan(void);
/*
* Initialise threads.
*/
void
initThreads(void)
{
/* Get a handle on the thread class */
ThreadClass = lookupClass(addString(THREADCLASS));
assert(ThreadClass != 0);
/* Allocate a thread to be the main thread */
currentThread = (thread*)alloc_object(ThreadClass, true);
assert(currentThread != 0);
currentThread->name = 0;
currentThread->priority = NORM_THREAD_PRIO;
currentThread->next = 0;
currentThread->PrivateInfo = THREAD_SUSPENDED;
currentThread->eetop = (ctx*)malloc(sizeof(ctx));
assert(currentThread->eetop != 0);
THREADINFO(currentThread->eetop);
currentThread->single_step = 0;
currentThread->daemon = 0;
currentThread->stillborn = 0;
currentThread->target = 0;
currentThread->group = (threadGroup*)execute_java_constructor(0, "java.lang.ThreadGroup", 0, "()V");
assert(currentThread->group != 0);
talive++;
/* Add thread into runQ */
resumeThread(currentThread);
/* Start any daemons we need */
finalman = startDaemon(&finaliserMan);
gcman = startDaemon(&gcMan);
}
/*
* Start a new thread running.
*/
void
startThread(thread* tid)
{
/* Allocate a stack context */
assert(tid->eetop == 0);
tid->eetop = (ctx*)malloc(sizeof(ctx));
assert(tid->eetop != 0);
tid->eetop->stackBase = (void*)malloc(THREADSTACKSIZE);
assert(tid->eetop->stackBase != 0);
tid->eetop->stackEnd = tid->eetop->stackBase + THREADSTACKSIZE;
tid->PrivateInfo = THREAD_SUSPENDED;
/* Construct the initial restore point. */
THREADINIT(tid->eetop, &firstStartThread);
talive++;
if (tid->daemon) {
tdaemon++;
}
/* Add thread into runQ */
resumeThread(tid);
}
/*
* All threads start here.
*/
static
void
firstStartThread(void)
{
/* Every thread starts with the interrupts off */
intsRestore();
/* Find the run()V method and call it */
do_execute_java_method(0, currentThread, "run", "()V", 0, 0);
do_execute_java_method(0, currentThread, "exit", "()V", 0, 0);
killThread(currentThread);
}
/*
* Resume a thread running.
*/
void
resumeThread(thread* tid)
{
intsDisable();
if (tid->PrivateInfo != THREAD_RUNNING) {
tid->PrivateInfo = THREAD_RUNNING;
/* Place thread on the end of its queue */
if (threadQhead[tid->priority] == 0) {
threadQhead[tid->priority] = tid;
threadQtail[tid->priority] = tid;
if (tid->priority > currentThread->priority) {
needReschedule = true;
}
}
else {
threadQtail[tid->priority]->next = tid;
threadQtail[tid->priority] = tid;
}
}
intsRestore();
}
/*
* Yield process to another thread of equal priority.
*/
void
yieldThread()
{
intsDisable();
if (threadQhead[currentThread->priority] != threadQtail[currentThread->priority]) {
/* Get the next thread and move me to the end */
threadQhead[currentThread->priority] = currentThread->next;
threadQtail[currentThread->priority]->next = currentThread;
threadQtail[currentThread->priority] = currentThread;
currentThread->next = 0;
needReschedule = true;
}
intsRestore();
}
/*
* Suspend a thread.
*/
void
suspendThread(thread* tid)
{
thread** ntid;
intsDisable();
if (tid->PrivateInfo != THREAD_SUSPENDED) {
tid->PrivateInfo = THREAD_SUSPENDED;
for (ntid = &threadQhead[tid->priority]; *ntid != 0; ntid = &(*ntid)->next) {
if (*ntid == tid) {
*ntid = tid->next;
if (tid == currentThread) {
reschedule();
}
break;
}
}
}
intsRestore();
}
/*
* Suspend a thread on a queue.
*/
void
suspendOnQThread(thread* tid, thread** queue)
{
thread** ntid;
assert(blockInts == 1);
if (tid->PrivateInfo != THREAD_SUSPENDED) {
tid->PrivateInfo = THREAD_SUSPENDED;
for (ntid = &threadQhead[tid->priority]; *ntid != 0; ntid = &(*ntid)->next) {
if (*ntid == tid) {
*ntid = tid->next;
/* Insert onto head of lock wait Q */
tid->next = *queue;
*queue = tid;
if (tid == currentThread) {
reschedule();
}
break;
}
}
}
}
/*
* Kill thread.
*/
void
killThread(thread* tid)
{
thread** ntid;
intsDisable();
if (tid->PrivateInfo != THREAD_DEAD) {
/* Get thread of runq (if it needs it) */
if (tid->PrivateInfo == THREAD_RUNNING) {
for (ntid = &threadQhead[tid->priority]; *ntid != 0; ntid = &(*ntid)->next) {
if (*ntid == tid) {
*ntid = tid->next;
break;
}
}
}
tid->PrivateInfo = THREAD_DEAD;
talive--;
if (tid->daemon) {
tdaemon--;
}
/* If we only have daemons left, then everyone is dead. */
if (talive == tdaemon) {
/* Am I suppose to close things down nicely ?? */
exit(0);
}
/* Thread is garbage collected, don't worry about freeing it. */
/* Run something else */
needReschedule = true;
}
intsRestore();
}
/*
* Change thread priority.
*/
void
setPriorityThread(thread* tid, int prio)
{
thread** ntid;
if (tid->PrivateInfo == THREAD_SUSPENDED) {
tid->priority = prio;
return;
}
intsDisable();
/* Remove from current thread list */
for (ntid = &threadQhead[tid->priority]; *ntid != 0; ntid = &(*ntid)->next) {
if (*ntid == tid) {
*ntid = tid->next;
break;
}
}
/* Insert onto a new one */
tid->priority = prio;
if (threadQhead[prio] == 0) {
threadQhead[prio] = tid;
threadQtail[prio] = tid;
if (prio > currentThread->priority) {
needReschedule = true;
}
}
else {
threadQtail[prio]->next = tid;
threadQtail[prio] = tid;
}
intsRestore();
}
/*
* Put a thread to sleep.
*/
void
sleepThread(long long time)
{
abort();
}
/*
* Is this thread alive?
*/
bool
aliveThread(thread* tid)
{
return (tid->PrivateInfo != THREAD_DEAD ? true : false);
}
/*
* How many stack frames have I invoked?
*/
long
framesThread(thread* tid)
{
long count;
THREADFRAMES(tid, count);
return (count);
}
/*
* Reschedule the thread.
* Called whenever a change in the running thread is required.
*/
void
reschedule(void)
{
int i;
thread* lastThread;
int b;
/* Check events - we may release a high priority thread */
checkEvents(false);
for (;;) {
for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--) {
if (threadQhead[i] != 0) {
if (threadQhead[i] != currentThread) {
b = blockInts;
lastThread = currentThread;
currentThread = threadQhead[i];
THREADSWITCH(currentThread->eetop, lastThread->eetop);
blockInts = b;
}
/* Now we kill the schedule and turn ints
back on */
needReschedule = false;
return;
}
}
/* Nothing to run - wait for external event */
checkEvents(true);
}
}
/*
* Start a daemon thread.
*/
static
thread*
startDaemon(void* func)
{
thread* tid;
tid = (thread*)alloc_object(ThreadClass, true);
assert(tid != 0);
tid->name = 0;
tid->priority = MAX_THREAD_PRIO;
tid->next = 0;
tid->PrivateInfo = THREAD_SUSPENDED;
tid->eetop = (ctx*)malloc(sizeof(ctx));
assert(tid->eetop != 0);
tid->eetop->stackBase = (void*)malloc(THREADSTACKSIZE);
assert(tid->eetop->stackBase != 0);
tid->eetop->stackEnd = tid->eetop->stackBase + THREADSTACKSIZE;
tid->single_step = 0;
tid->daemon = 1;
tid->stillborn = 0;
tid->target = 0;
tid->group = 0;
/* Construct the initial restore point. */
THREADINIT(tid->eetop, func);
talive++;
tdaemon++;
/* Add thread into runQ */
resumeThread(tid);
return (tid);
}